1 //+-----------------------------------------------------------------------
3 // Copyright (c) Microsoft Corporation. All rights reserved.
7 // This file has all the Low Rights code. This is bascially the code that detects
8 // if the process is running with high privileges and the code that'll restart the
9 // process with low privileges.
11 // One key change from the IE code is that we run restricted by default. The change
12 // is in the function ShouldProcessBeRestricted().
15 // 2005/03/10 - Created the file based on code we got from Anantha Ganjam in the IE team.
16 // 2007/07/06 - [....] - Switched to using the LSA APIs to replace the use of LookupPrivilegeValue()
17 // with a more efficient version for our scenario.
18 // In lieu of SDK documentation of the LSA APIs, there's this KB article:
19 // http://support.microsoft.com/kb/132958.
21 // Ported Windows->DevDiv. See SourcesHistory.txt.
23 //------------------------------------------------------------------------
25 #include "Precompiled.hxx"
26 #include "LoRights.hxx"
27 #include "..\inc\registry.hxx"
29 // <NTLSA.H> Substitute
31 // In Windows we got all these definitions (directly or indirectly) from ntlsa.h, which is not included in
32 // DevDiv's SDK. Trying to transplant it fails because it's apparently incompatible with the DevDiv versions
33 // of other headers. ntddk.h & ntdef.h also contain most of these definitions, but they cause too many
34 // redefinition errors with winnt.h. (There are multiple reports of this happening on the web. People
35 // try to work around by including ntddk.h in a namespace, but that by itself doesn't seem enough.)
37 #include <ntsecapi.h> // This gives us most of what ntlsa.h did in Windows.
42 RtlInitUnicodeString (
43 PUNICODE_STRING DestinationString
,
48 #ifndef STATUS_SUCCESS
49 #define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
53 #define InitializeObjectAttributes( p, n, a, r, s ) { \
54 (p)->Length = sizeof( LSA_OBJECT_ATTRIBUTES ); \
55 (p)->RootDirectory = r; \
56 (p)->Attributes = a; \
57 (p)->ObjectName = n; \
58 (p)->SecurityDescriptor = s; \
59 (p)->SecurityQualityOfService = NULL; \
65 LsaLookupPrivilegeValue(
66 __in LSA_HANDLE PolicyHandle
,
67 __in PLSA_UNICODE_STRING Name
,
73 const int cMaxAttrLen
= 512;
74 const int cMaxSidName
= 512;
76 void FreeSIDArray(__inout_ecount(cSIDs
) SID_AND_ATTRIBUTES
*pSIDs
, unsigned cSIDs
)
78 for (DWORD i
= 0; i
< cSIDs
; i
++)
80 delete [] static_cast<BYTE
*>(pSIDs
[i
].Sid
);
85 // This is the function that launches our process with restricted tokens
86 BOOL
LaunchRestrictedProcess(__in LPCWSTR lpwszCmdLine
, __in_ecount(dwDisabledPrivilegeCount
) PLUID_AND_ATTRIBUTES pDisabledPrivileges
, DWORD dwDisabledPrivilegeCount
)
89 DWORD dwStatus
= ERROR_SUCCESS
;
90 DWORD dwDisabledSidCount
= 0;
91 PSID_AND_ATTRIBUTES pDisabledSids
= NULL
;
93 // lpwszCmdLine is not traced, because WinMain actually passes NULL.
94 EventWriteWpfHostUm_LaunchingRestrictedProcess();
96 //For the current impementation this returns the list of SIDS in g_disableSIDS
97 // which happens to be Power User and Admin
98 if (ERROR_SUCCESS
== (dwStatus
= GetDisabledSids( &pDisabledSids
, &dwDisabledSidCount
)))
100 // if we for some reason we cannot start a restricted process
101 // the only option we have is to start process normally.
102 if (ERROR_SUCCESS
== (dwStatus
= CreateRestrictedProcess( pDisabledSids
,
105 dwDisabledPrivilegeCount
,
111 FreeSIDArray(pDisabledSids
, dwDisabledSidCount
);
116 // This functions checks to see the registry if the key to restrict the process is set
117 BOOL
ShouldProcessBeRestricted(void)
120 LONG lRet
= ERROR_SUCCESS
;
122 DWORD dwUnrestricted
= 0;
123 DWORD dwSize
= sizeof(dwUnrestricted
);
124 OSVERSIONINFOEX osVersion
;
125 osVersion
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOEX
);
127 if ( GetVersionEx( (LPOSVERSIONINFO
) & osVersion
) )
129 if ((osVersion
.dwMajorVersion
== 5) && (osVersion
.dwMinorVersion
== 1))
131 // We are on XP here, terminate the process if SP level < SP2
132 if (osVersion
.wServicePackMajor
< 2)
137 // Check the RunUnrestricted registry value.
138 // If it exists and is 0 then run PresentationHost with no restrictions or as the user
139 // If it doesn't exist or if it exists and is set to 1, then run IE in restricted mode
140 lRet
= RegOpenKeyEx( HKEY_LOCAL_MACHINE
,
146 if (ERROR_SUCCESS
== lRet
)
148 lRet
= RegQueryValueEx( hKey
,
149 RegValue_RunUnrestricted
,
152 (LPBYTE
)&dwUnrestricted
,
154 if (ERROR_SUCCESS
== lRet
&& dwUnrestricted
== 1)
163 // The logic here is essentially checking to see of the current process is already restricted
164 // If it is then we do not have to do additional work.
165 BOOL
IsCurrentProcessRestricted(__in_ecount(dwDisabledPrivilegesCount
) PLUID_AND_ATTRIBUTES pDisabledPrivileges
, DWORD dwDisabledPrivilegesCount
)
167 static BOOL s_bInit
= FALSE
;
168 static BOOL s_bRet
= TRUE
;
170 if (FALSE
== s_bInit
)
172 // Checks registry to see if this process needs to be disabled
173 if (ShouldProcessBeRestricted())
175 DWORD dwStatus
= ERROR_SUCCESS
;
176 DWORD dwDisabledSidCount
= 0;
177 PSID_AND_ATTRIBUTES pDisabledSids
= NULL
;
179 // Extract ---- SIDs (currently Admin and power user)
180 if (ERROR_SUCCESS
== (dwStatus
= GetDisabledSids( &pDisabledSids
, &dwDisabledSidCount
)))
182 // if the current process is already restricted then we do not need to do anything more
183 if (!IsCurrentPresentationHostRestricted( pDisabledSids
,
186 dwDisabledPrivilegesCount
))
191 FreeSIDArray(pDisabledSids
, dwDisabledSidCount
);
199 // This function takes the preset list of restricted groups and priviliges and then
200 // checks to see if any of them exist on the current token.
201 // If they do then the process is not restricted and needs to be restricted.
202 BOOL
IsCurrentPresentationHostRestricted(__in PSID_AND_ATTRIBUTES pDisabledSids
,
203 __in DWORD dwDisabledSidCount
,
204 __in PLUID_AND_ATTRIBUTES pDisabledPrivileges
,
205 __in DWORD dwDisabledPrivilegeCount
)
207 // If we cannot open a process token for query we cannot generate a restricted token from this token
208 // If we fail here we will try to create a restricted token which is bound to fail
209 // Either case for appcompat we need to just open PresenationHost as-is. If not PresenationHost will never launch
213 // Check if the current PresentationHost is restricted
214 // The restrictions we put on PresenationHost are
215 // 1. Disable in Administrators and Power Users groups
216 // 2. Remove a set of Privileges
217 // If the current token has these settings then we are already in restricted PresentationHost
219 // Open token for the current process , this function actually is quite generic
220 if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY
, &hProcToken
))
222 // The structure of this API is such that it returns an error to indicate success
223 // when getting size of buffer that needs to be allocated
225 if (!GetTokenInformation(hProcToken
, TokenGroupsAndPrivileges
, NULL
, 0, &dwSize
) &&
226 GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
228 BYTE userSID
[SECURITY_MAX_SID_SIZE
];
229 PTOKEN_GROUPS_AND_PRIVILEGES pTokenGroups
;
230 pTokenGroups
= reinterpret_cast<PTOKEN_GROUPS_AND_PRIVILEGES
>(new BYTE
[dwSize
]);
233 fRet
= false; // That's a safer way to fail.
237 // This is a call to query for a token of the process with information on groups and priviliges
238 if ( GetTokenInformation(hProcToken
, TokenGroupsAndPrivileges
, pTokenGroups
, dwSize
, &dwSize
) &&
239 ERROR_SUCCESS
== GetUserSid(hProcToken
, &userSID
))
241 // If any of our restricted set is part of the groups or priviliges extracted then
242 // this process is not restricted and needs to be stripped.
243 if ( FALSE
== CheckForDisabledSids(pTokenGroups
->Sids
, pTokenGroups
->SidCount
, pDisabledSids
, dwDisabledSidCount
) ||
244 FALSE
== CheckForRestrictedSids(pTokenGroups
->RestrictedSids
, pTokenGroups
->RestrictedSidCount
, pDisabledSids
, dwDisabledSidCount
, &userSID
) ||
245 FALSE
== CheckForPrivileges(pTokenGroups
->Privileges
, pTokenGroups
->PrivilegeCount
, pDisabledPrivileges
, dwDisabledPrivilegeCount
))
250 delete [] reinterpret_cast<BYTE
*>(pTokenGroups
);
253 CloseHandle(hProcToken
);
259 // This is the function where the actual stripping of the token takes place, it accepts the Groups and priviliges to strip
260 DWORD
CreateRestrictedProcess( __in PSID_AND_ATTRIBUTES pDisabledSids
,
261 __in DWORD dwDisabledSidCount
,
262 __in PLUID_AND_ATTRIBUTES pDisabledPrivileges
,
263 __in DWORD dwDisabledPrivilegeCount
,
264 __in LPCWSTR lpwszCmdLine
)
266 // Get the process token, add disabled SIDs for Administrators and Power Users groups
267 // Also remove the above listed privileges
268 // Create a new PresenationHost process with this token
269 DWORD dwStatus
= ERROR_SUCCESS
;
270 HANDLE hProcToken
= NULL
;
271 HANDLE hRestrictedToken
= NULL
;
273 // Ther current PresentationHost is not restriced, so we create a restricted token that
274 // disables Administrators and Power Users groups if present and removes
275 // a set of Privileges and adds restrictions
276 if (OpenProcessToken(GetCurrentProcess(),
277 TOKEN_READ
|TOKEN_WRITE
|TOKEN_ASSIGN_PRIMARY
|TOKEN_DUPLICATE
,
281 // Extracts SID for current user, this is the priviliges that the current process will have, and
282 // even if user is admin or power user we will strip those.
283 BYTE userSID
[SECURITY_MAX_SID_SIZE
];
284 if (ERROR_SUCCESS
== (dwStatus
= GetUserSid(hProcToken
, &userSID
)))
286 // This is where we create a token without the priviliges and groups that we need to disable
287 if (CreateRestrictedToken( hProcToken
,
288 0/*WRITE_RESTRICTED*/ ,
291 dwDisabledPrivilegeCount
,
293 0, /* dwRestrictedSidCount*/
294 NULL
, /* pRestrictedSids*/
297 WCHAR wszPath
[MAX_PATH
];
298 LPWSTR pwszArgs
= NULL
;
299 STARTUPINFO si
= { sizeof(si
) };
300 PROCESS_INFORMATION pi
;
302 ZeroMemory(&pi
, sizeof(pi
));
303 if (NULL
== lpwszCmdLine
)
304 pwszArgs
= GetCommandLineW();
306 pwszArgs
= (LPWSTR
)lpwszCmdLine
;
307 if (GetModuleFileNameW(NULL
, wszPath
, ARRAY_SIZE(wszPath
)))
309 // allow access to current user sid
310 PSID pAccessAllowedSIDS
[1] = { &userSID
};
311 // Allow query and Impersonate permissions to these users on the token
312 if (ERROR_SUCCESS
== (dwStatus
= AddSidsToToken(hRestrictedToken
, pAccessAllowedSIDS
, 1 , GENERIC_ALL
/*TOKEN_QUERY|TOKEN_IMPERSONATE*/ )))
315 // Launch the process with a restricted token
316 if (CreateProcessAsUser(hRestrictedToken
,
328 WaitForInputIdle(pi
.hProcess
, 5000);
329 CloseHandle(pi
.hProcess
);
330 CloseHandle(pi
.hThread
);
334 dwStatus
= GetLastError();
340 dwStatus
= GetLastError();
342 CloseHandle(hRestrictedToken
);
346 dwStatus
= GetLastError();
349 CloseHandle(hProcToken
);
354 dwStatus
= GetLastError();
360 // returns false if any of ---- sids are on the current token list as anything but Deny_only
361 BOOL
CheckForDisabledSids(__in PSID_AND_ATTRIBUTES pSids
,
362 __in DWORD dwSidCount
,
363 __in PSID_AND_ATTRIBUTES pDisabledSids
,
364 __in DWORD dwDisabledSidCount
)
367 DWORD dwGroupCount
= 0;;
370 for (dwGroupCount
=0; dwGroupCount
<dwSidCount
; dwGroupCount
++)
372 for (dwCount
=0; dwCount
< dwDisabledSidCount
; dwCount
++)
374 if (EqualSid(pSids
[dwGroupCount
].Sid
, pDisabledSids
[dwCount
].Sid
))
376 if (!(pSids
[dwGroupCount
].Attributes
& SE_GROUP_USE_FOR_DENY_ONLY
))
387 //check if the restricted tokens contain any of the tokens we want to strip
388 BOOL
CheckForRestrictedSids(__in PSID_AND_ATTRIBUTES pSids
,
389 __in DWORD dwSidCount
,
390 __in PSID_AND_ATTRIBUTES pRestrictedSids
,
391 __in DWORD dwRestrictedSidCount
,
395 DWORD dwGroupCount
= 0;;
398 // if current user is admin or power user we need to strip
399 for (dwCount
= 0; dwCount
< dwRestrictedSidCount
; dwCount
++)
401 if (EqualSid(pUserSid
, pRestrictedSids
[dwCount
].Sid
))
408 // if the restricted SIDs contain admin or power user return false since we need to strip
411 for (dwGroupCount
= 0; dwGroupCount
< dwSidCount
; dwGroupCount
++)
413 for (dwCount
= 0; dwCount
< dwRestrictedSidCount
; dwCount
++)
415 if (EqualSid(pSids
[dwGroupCount
].Sid
, pRestrictedSids
[dwCount
].Sid
))
427 // This checks to see if any of the priviliges we have predetermined are part of the current list. If they are we return false else true
428 BOOL
CheckForPrivileges(__in PLUID_AND_ATTRIBUTES pPrivileges
,
429 __in DWORD dwPrivilegeCount
,
430 __in PLUID_AND_ATTRIBUTES pDisabledPrivileges
,
431 __in DWORD dwDisabledPrivilegeCount
)
434 DWORD dwPrivCount
= 0;;
437 for (dwPrivCount
=0; dwPrivCount
<dwPrivilegeCount
; dwPrivCount
++)
439 for (dwCount
=0; dwCount
<dwDisabledPrivilegeCount
; dwCount
++)
441 if (0 == memcmp(&pPrivileges
[dwPrivCount
].Luid
, &pDisabledPrivileges
[dwCount
].Luid
, sizeof(LUID
)))
451 // Iterates over the predefined list of disabled SIDs we have and obtains the SID values for them.
452 // Call FreeSIDArray() when done with the returned data.
453 DWORD
GetDisabledSids(__out PSID_AND_ATTRIBUTES
*ppDisabledSids
, __out DWORD
*pdwDisabledSidCount
)
455 DWORD dwStatus
= ERROR_SUCCESS
;
458 PSID_AND_ATTRIBUTES pDisabledSids
;
460 pDisabledSids
= new SID_AND_ATTRIBUTES
[ARRAY_SIZE(g_disableSIDS
)];
463 memset(pDisabledSids
, 0, (ARRAY_SIZE(g_disableSIDS
))*sizeof(SID_AND_ATTRIBUTES
));
464 for (dwCount
=0; dwCount
<ARRAY_SIZE(g_disableSIDS
); dwCount
++)
466 pDisabledSids
[dwCount
].Sid
= new BYTE
[SECURITY_MAX_SID_SIZE
];
467 if (pDisabledSids
[dwCount
].Sid
)
469 dwSidSize
= SECURITY_MAX_SID_SIZE
;
470 if (!CreateWellKnownSid(g_disableSIDS
[dwCount
], NULL
, pDisabledSids
[dwCount
].Sid
, &dwSidSize
))
472 dwStatus
= GetLastError();
478 dwStatus
= ERROR_NOT_ENOUGH_MEMORY
;
483 if (dwStatus
== ERROR_SUCCESS
)
485 *ppDisabledSids
= pDisabledSids
;
486 *pdwDisabledSidCount
= ARRAY_SIZE(g_disableSIDS
);
490 FreeSIDArray(pDisabledSids
, ARRAY_SIZE(g_disableSIDS
));
495 dwStatus
= ERROR_NOT_ENOUGH_MEMORY
;
500 //This call gets a list of disabled priviliges
501 DWORD
GetDisabledPrivileges(__out PLUID_AND_ATTRIBUTES
*ppDisabledPrivileges
, __out DWORD
*pdwDisabledPrivlegeCount
)
503 DWORD dwStatus
= ERROR_SUCCESS
;
505 *ppDisabledPrivileges
= NULL
;
506 *pdwDisabledPrivlegeCount
= 0;
507 PLUID_AND_ATTRIBUTES pDisabledPrivileges
;
509 pDisabledPrivileges
= new LUID_AND_ATTRIBUTES
[ARRAY_SIZE(g_ppwszPrivileges
)];
510 if (pDisabledPrivileges
)
513 LSA_HANDLE PolicyHandle
;
514 LSA_OBJECT_ATTRIBUTES ObjectAttributes
;
515 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0L, NULL
, NULL
);
517 // Instead of calling LookupPrivilegeValue call LsaLookupPrivilegeValue
518 // to avoid LsaOpenPolicy/LsaClose inside the loop.
519 ntStatus
= LsaOpenPolicy(NULL
,
523 if (ntStatus
== STATUS_SUCCESS
)
525 UNICODE_STRING uName
;
526 for(dwCount
=0; dwCount
<ARRAY_SIZE(g_ppwszPrivileges
); dwCount
++)
528 // Initialize a counted string for LsaLookupPrivilegeValue. The buffer of uName points to the WSTR argument
529 RtlInitUnicodeString(&uName
, g_ppwszPrivileges
[dwCount
]);
530 ntStatus
= LsaLookupPrivilegeValue(PolicyHandle
, &uName
, &pDisabledPrivileges
[dwCount
].Luid
);
531 if (ntStatus
!= STATUS_SUCCESS
)
533 dwStatus
= LsaNtStatusToWinError(ntStatus
);
538 ntStatus
= LsaClose(PolicyHandle
);
539 if (ntStatus
!= STATUS_SUCCESS
)
541 dwStatus
= LsaNtStatusToWinError(ntStatus
);
546 dwStatus
= LsaNtStatusToWinError(ntStatus
);
549 if (dwStatus
== ERROR_SUCCESS
)
551 *ppDisabledPrivileges
= pDisabledPrivileges
;
552 *pdwDisabledPrivlegeCount
= ARRAY_SIZE(g_ppwszPrivileges
);
556 delete [] pDisabledPrivileges
;
561 dwStatus
= ERROR_NOT_ENOUGH_MEMORY
;
567 //Extracts the user sid for the process
568 DWORD
GetUserSid(__in HANDLE hProcToken
, __out_bcount(SECURITY_MAX_SID_SIZE
) PSID pSid
)
570 DWORD dwError
= ERROR_SUCCESS
;
571 DWORD cbTokenInfo
= 0;
573 // GetTokenInformation(TokenUser) pupulates a TOKEN_USER structure immediately followed by a
574 // SID structure. TOKEN_USER::User.Sid points to the adjoined SID structure.
575 BYTE buffer
[sizeof TOKEN_USER
+ SECURITY_MAX_SID_SIZE
];
576 TOKEN_USER
*pTokenUser
= reinterpret_cast<TOKEN_USER
*>(buffer
);
577 if (GetTokenInformation(hProcToken
, TokenUser
, pTokenUser
, sizeof buffer
, &cbTokenInfo
))
579 CopySid(SECURITY_MAX_SID_SIZE
, pSid
, pTokenUser
->User
.Sid
);
583 dwError
= GetLastError();
589 // This call adds a list of sids to a token
590 DWORD
AddSidsToToken(__in HANDLE hRestrictedToken
, __in PSID
*ppSids
, __in DWORD dwSids
, __in DWORD dwAccess
)
592 PACL pOldDacl
= NULL
;
593 PACL pNewDacl
= NULL
;
597 DWORD dwError
= ERROR_SUCCESS
;
598 PSECURITY_DESCRIPTOR pSD
= NULL
;
600 // GetKernelObjectSecurity() appends various SIDs to a SECURITY_DESCRIPTOR header.
601 // We first query for the needed space.
602 if (!GetKernelObjectSecurity(hRestrictedToken
, DACL_SECURITY_INFORMATION
, NULL
, cbSD
, &cbSD
) &&
603 (dwError
= GetLastError()) == ERROR_INSUFFICIENT_BUFFER
)
605 pSD
= reinterpret_cast<PSECURITY_DESCRIPTOR
>(new BYTE
[cbSD
]);
608 dwError
= ERROR_SUCCESS
;
609 if (GetKernelObjectSecurity(hRestrictedToken
, DACL_SECURITY_INFORMATION
, pSD
, cbSD
, &cbSD
))
611 if (GetSecurityDescriptorDacl(pSD
, &fDaclPresent
, &pOldDacl
, &fDaclDefaulted
))
614 if (ERROR_SUCCESS
== (dwError
= SetSidsOnAcl(ppSids
, dwSids
, pOldDacl
, &pNewDacl
, &cbDacl
, dwAccess
, 0)))
617 TOKEN_DEFAULT_DACL tokenDefaultDACL
;
619 tokenDefaultDACL
.DefaultDacl
= pNewDacl
;
620 cbTokenInfo
= sizeof(tokenDefaultDACL
)+cbDacl
;
622 if (!SetTokenInformation(hRestrictedToken
, TokenDefaultDacl
, &tokenDefaultDACL
, cbTokenInfo
))
624 dwError
= GetLastError();
631 dwError
= GetLastError();
636 dwError
= GetLastError();
638 delete [] reinterpret_cast<BYTE
*>(pSD
);
642 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
649 //gives access to built in users and current users, current value passed in also includes IEGroup but that must die.
650 BOOL
SetSidsOnAcl(__in PSID
*ppSids
,
652 __in PACL pAclSource
,
653 __out PACL
*pAclDestination
,
654 __out DWORD
*pcbDacl
,
655 __in DWORD AccessMask
,
658 DWORD dwError
= ERROR_SUCCESS
;
662 PACCESS_ALLOWED_ACE pAce
;
664 ACL_SIZE_INFORMATION AclInfo
;
666 if (pAclSource
!= NULL
)
668 if (GetAclInformation(pAclSource
, &AclInfo
, sizeof(ACL_SIZE_INFORMATION
), AclSizeInformation
))
670 // compute size for new Acl, based on addition or subtraction of Ace
671 dwNewAclSize
= AclInfo
.AclBytesInUse
;
674 for (iSid
= 0; iSid
< dwSids
; iSid
++)
676 DWORD addend
= GetLengthSid(ppSids
[iSid
]);
677 C_ASSERT(sizeof(ACCESS_ALLOWED_ACE
) >= sizeof(DWORD
));
678 hr
= DWordAdd(addend
, sizeof(ACCESS_ALLOWED_ACE
) - sizeof(DWORD
), &addend
);
681 return ERROR_INVALID_DATA
;
683 hr
= DWordAdd(dwNewAclSize
, addend
, &dwNewAclSize
);
686 return ERROR_INVALID_DATA
;
690 *pAclDestination
= reinterpret_cast<PACL
>(new BYTE
[dwNewAclSize
]);
691 if (*pAclDestination
)
693 *pcbDacl
= dwNewAclSize
;
694 // initialize new Acl
695 if (InitializeAcl(*pAclDestination
, dwNewAclSize
, ACL_REVISION
))
697 for (iSid
= 0; iSid
< dwSids
; iSid
++)
699 // if appropriate, add ace representing pSid
700 PACCESS_ALLOWED_ACE pNewAce
;
701 if (AddAccessAllowedAce(*pAclDestination
, ACL_REVISION
, AccessMask
, ppSids
[iSid
]))
703 // get pointer to ace we just added, so we can change the AceFlags
704 if (GetAce(*pAclDestination
, iSid
, (void**)&pNewAce
))
705 pNewAce
->Header
.AceFlags
= AceFlags
;
708 dwError
= GetLastError();
714 dwError
= GetLastError();
718 if (ERROR_SUCCESS
== dwError
)
720 // copy existing aces to new Acl
721 for (AceCounter
= 0 ; AceCounter
< AclInfo
.AceCount
; AceCounter
++)
723 // fetch existing ace
724 if (GetAce(pAclSource
, AceCounter
, (LPVOID
*) & pAce
))
726 if (!AddAce(*pAclDestination
, ACL_REVISION
, MAXDWORD
, pAce
, ((PACE_HEADER
)pAce
)->AceSize
))
728 dwError
= GetLastError();
734 dwError
= GetLastError();
742 dwError
= GetLastError();
747 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
752 dwError
= GetLastError();
757 *pAclDestination
= NULL
;
761 if (dwError
!= ERROR_SUCCESS
&& *pAclDestination
)
763 delete *pAclDestination
;
764 *pAclDestination
= NULL
;
770 BOOL
IsPresentationHostHighIntegrity()
772 DWORD pid
= GetCurrentProcessId();
773 return GetProcessIntegrityLevel(pid
) >= (int)SECURITY_MANDATORY_HIGH_RID
;